package com.fingard.dsp.bank.directbank.jscb01;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptData;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptDataHelper;
import com.fingard.dsp.bank.directConfig.FtpSet;
import com.fingard.dsp.bank.directConfig.ReceiptProConfig;
import com.fingard.dsp.bank.directbank.bankInterface.IReceiptPro;
import com.fingard.dsp.bank.reqrespobj.downloadreceipt.ReqQryReceipt;
import com.fingard.dsp.bank.reqrespobj.downloadreceipt.RetAtsReceipt;
import com.fingard.io.FileHelper;
import com.fingard.net.ConnState;
import com.fingard.net.FtpPortClient;
import com.fingard.net.FtpReceiver;
import com.fingard.net.SftpPortClient;
import com.fingard.text.MFSHelper;
import com.fingard.text.StringHelper;
import com.fingard.util.SmbFileUtil;
import com.fingard.util.ZipHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Parker on 2020-02-27.
 * @version 1.0
 */
public class JSCB01ReceiptPro extends JSCB01Base implements IReceiptPro {
    @Override
    public RetAtsReceipt qryReceiptOneDay(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay) throws Exception {
        String qryDay8 = Format.Date8Format.format(pOneDay);
        //下载回单数据文件及回单文件
        String dataFileInfo = downDataFile(pConfig, pReqReceipt, pOneDay);
        //文件名_记录条数_字段数
        String[] dataFileInfoArr = dataFileInfo.split("_");
        String localpath = pConfig.getSaveSubDir(pReqReceipt.reqHeader, pOneDay) + File.separator + qryDay8;
        if (dataFileInfoArr.length != 3) {
            WriteBankLogLn("回单数据文件查询失败。");
            return null;
        }
        String dateFile = localpath + File.separator + dataFileInfoArr[0];
        if (!new File(dateFile).exists()) {
            WriteBankLogLn("回单数据文件下载失败：" + dataFileInfoArr[0]);
            return null;
        }
        String fileContext = FileHelper.readFileText(dateFile, getCharset());
        StringBuilder sb = new StringBuilder();
        ArrayList<String[]> textArray = MFSHelper.getTextArray(fileContext, "|", Integer.parseInt(dataFileInfoArr[2]), Integer.parseInt(dataFileInfoArr[1]) + 1, sb);
        if (StringHelper.hasAnyChar(sb.toString())) {
            WriteBankLogLn("回单数据文件解析失败：" + sb.toString());
            return null;
        }
        ReceiptDataHelper receiptHelper = new ReceiptDataHelper(pReqReceipt.reqHeader.tenant, pOneDay);//回单数据保存类，分区分表

        try {
            for (int i = 1; i < textArray.size(); i++) {
                String[] text = textArray.get(i);
                ReceiptData rcpt = new ReceiptData();
                rcpt.ownAct = pReqReceipt.actNum;
                rcpt.bank = "20013";
                rcpt.srcSys = "JSCB01";
                rcpt.istNbr = text[0].replace("\n", "");//SERIAL_NO 流水号
                rcpt.receiptNo = rcpt.istNbr;//SERIAL_NO 流水号
                //ATSES-24143 dsp添加江苏银行电子回单匹配字段
                String transNo = text[15].trim();//明细的流水号 取值PURPOSE 实际值,如：柜员流水:c00004000363  附言:LZ20031100024878 柜员流水号可能为空 如：柜员流水:  附言: 结息账号:71100101307016395
                if (transNo.split(" ")[0].split(":").length > 1) {
                    transNo = transNo.split(" ")[0].split(":")[1].trim();
                    /**银行流水号*/
                    rcpt.bnkSeqNo = transNo;
                }
                /**业务参考号*/
                rcpt.busRef = text[3]+text[17]+text[1];//本方账号+对方账号+日期yyyyMMdd

                rcpt.busDate = Integer.parseInt(qryDay8);
                String TRAN_DATE = text[1];
                if (!qryDay8.equals(TRAN_DATE)) {
                    WriteBankLogLn(rcpt.receiptNo + "回单数据的日期" + TRAN_DATE + "与预期" + qryDay8 + "不符");
                }
                String cdFlag = text[29];
                if ("C".equals(cdFlag)) {
                    rcpt.moneyWay = "2";
                } else if ("D".equals(cdFlag)) {
                    rcpt.moneyWay = "1";
                }
                rcpt.amount = new BigDecimal(text[10]);
                rcpt.voucherNo = text[9];
                rcpt.oppActNum = text[17];
                rcpt.oppActName = text[19];
                rcpt.cur = convertCurToATS(text[4]);
                int inRe = receiptHelper.insertIfNotExist(rcpt, true);
                WriteBankLogLn(rcpt.receiptNo + "写入数据库，影响行数：" + inRe);
            }
            FileHelper.deleteRecursive(dateFile);
            WriteBankLogLn(pReqReceipt.actNum + "，" + qryDay8 + "回单数据查询完成，删除数据文件并开始下载PDF回单文件");
            ArrayList<String> list = receiptHelper.getIstNbrList(pReqReceipt.actNum, pOneDay);
            WriteBankLogLn(pReqReceipt.actNum + "，" + qryDay8 + "需要进行下载的回单文件个数：" + list.size());
            if (list.size() <= 0) {
                return null;
            }
            //下载回单数据文件
            String filePath = downPDFFile(pConfig, pReqReceipt, pOneDay);
            if (StringHelper.isNullOrEmpty(filePath)) {
                return null;
            }
            getPdfFiles(pConfig, pReqReceipt, pOneDay, filePath, list);
            //是否删除下载的zip临时文件
            if (pConfig.deleteAfterUploaded) {
                WriteBankLogLn("删除" + filePath + ".zip");
                FileHelper.deleteFileIfExists(filePath + ".zip");
            }
            WriteBankLogLn("删除" + filePath);
            FileHelper.deleteRecursive(filePath);
        } catch (Exception ex) {
            this.WriteBankLogLn(ex);
        } finally {
            if (receiptHelper != null) {
                receiptHelper.close();
            }
        }
        return null;
    }

    /**
     * 公共方法，下载的日期目录中提取pdf文件
     */
    protected void getPdfFiles(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay, String pReceiptDir, List<String> dataList) {
        ReceiptDataHelper receiptHelper = null;//回单数据保存类，分区分表
        try {
            receiptHelper = new ReceiptDataHelper(pReqReceipt.reqHeader.tenant, pOneDay);
            File receiptDir = new File(pReceiptDir);

            int[] retVals = getPdfLoop(pConfig, pReqReceipt, pOneDay, receiptHelper, receiptDir, dataList);
            //[0]总数 [1]新增 [2]已存在
            WriteBankLogLn("目录" + pReceiptDir + "\r\n遍历总数" + retVals[0] + "，新增" + retVals[1] + "条，已存在" + (retVals[0] - retVals[1]) + "条");
        } catch (Exception ex) {
            this.WriteBankLogLn(ex);
        } finally {
            if (receiptHelper != null) {
                receiptHelper.close();
            }
        }
    }

    /**
     * 公共方法，提取pdf文件，农行是所有账号的回单一起提供，遍历所有pdf
     * [0]总数 [1]新增 [2]已存在
     */
    protected int[] getPdfLoop(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay, ReceiptDataHelper pReceiptHelper, File pDir, List<String> dataList) {
        String qryDay8 = Format.Date8Format.format(pOneDay);
        int[] retVals = new int[2];
        retVals[0] = 0;//总pdf个数
        retVals[1] = 0;//新增
        File[] files = pDir.listFiles();
        for (File eachFile : files) {
            try {
                if (eachFile.isDirectory()) {
                    int[] subVals = getPdfLoop(pConfig, pReqReceipt, pOneDay, pReceiptHelper, eachFile, dataList);
                    retVals[0] = retVals[0] + subVals[0];
                    retVals[1] = retVals[1] + subVals[1];
                }
                String[] nameAndExt = StringHelper.splitFileNameAndExt(eachFile.getName());
                if ("pdf".equalsIgnoreCase(nameAndExt[1])) {
                    retVals[0] = retVals[0] + 1;
                    //名称_回单编号_核心流水号_日期_账号
                    String[] nameSp = nameAndExt[0].split("_");
                    if (nameSp.length != 3) {
                        WriteBankLogLn("回单文件:" + eachFile.getName() + "文件名格式不符合预期");
                        continue;
                    }

                    for (String istNbr : dataList) {
                        if (nameSp[0].contains(istNbr)) {
                            //重命名
                            String renameToPath = pConfig.getSaveSubDir(pReqReceipt.reqHeader, pOneDay) + File.separator + qryDay8 + File.separator + pReqReceipt.actNum;
                            FileHelper.mkdirsIfNotExists(renameToPath);
                            renameToPath += File.separator + eachFile.getName();
                            File destFile = new File(renameToPath);
                            boolean reResult;
                            if (destFile.exists()) {
                                reResult = true;
                            } else {
                                reResult = eachFile.renameTo(destFile);
                            }
                            if (reResult) {
                                //数据库中存储的路径是相对pConfig.localSaveMainDir的相对路径
                                String relativePath = StringHelper.getRelativePath(destFile.getAbsolutePath(), pConfig.localSaveMainDir);
                                int inRe = pReceiptHelper.updateDownState(pReqReceipt.actNum, istNbr, relativePath, eachFile.getName(), "2");
                                if (inRe > 0) {
                                    retVals[1] = retVals[1] + 1;
                                }
                                WriteBankLogLn("回单编号" + istNbr + "，文件" + eachFile.getName() + "下载成功，重命名成功，更新影响行数：" + inRe);
                            } else {
                                WriteBankLogLn("回单编号" + istNbr + "重命名失败：\r\n" + eachFile.getAbsolutePath() + "\r\n重命名为：\r\n" + renameToPath);
                            }
                            break;
                        }
                    }
                }
            } catch (Exception ex) {
                WriteBankLogLn(ex, eachFile.getAbsolutePath());
            }
        }
        return retVals;
    }

    //查询回单数据文件
    private String downDataFile(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay) {
        StringBuilder retStr = new StringBuilder();
        String qryDay8 = Format.Date8Format.format(pOneDay);
        try {
            WriteBankLogLn("查询回单数据文件.....");
            JSCB01Header header = new JSCB01Header();
            header.transCode = "200125";
            header.reqSeqNo = getQryTransID();
            XmlTextWriter xmlWriter = new XmlTextWriter();
            xmlWriter.autoFormat = false;
            writeCommonHeader(xmlWriter, header);
            xmlWriter.writeStartElement("body");
            xmlWriter.writeElementString("acno", pReqReceipt.actNum);
            xmlWriter.writeElementString("cur_code", convertCurToBank(pReqReceipt.actCur));
            xmlWriter.writeElementString("start_date", qryDay8);
            xmlWriter.writeElementString("end_date", qryDay8);
            xmlWriter.writeElementString("serial_no", "");
            xmlWriter.writeElementString("cert_no", "");
            xmlWriter.writeElementString("start_amt", "");
            xmlWriter.writeElementString("end_amt", "");
            xmlWriter.writeEndDocument();

            String[] retStrArr = sendToBank(xmlWriter.toXmlString());
            //String[] retStrArr = new String[]{"","<ap><head><tr_code>200125</tr_code><cms_corp_no>2011262835</cms_corp_no><user_no>001</user_no><req_no>A0001120200110080000011</req_no><serial_no>28235566</serial_no><tr_acdt>20200227</tr_acdt><tr_time>172335</tr_time><succ_flag>0</succ_flag><ret_info>交易成功</ret_info><ret_code>0000</ret_code><ext_info></ext_info><reserved></reserved><file_flag>1</file_flag><org_code>2056</org_code></head><body><record_num>113</record_num><host_serial_no>28235567</host_serial_no><stat>9</stat><file_name>2020022728235567.query</file_name><field_num>40</field_num></body></ap>"};

            if (retStrArr[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                XmlTextReader tmpBkReader = loadBankRespXmlReader(retStrArr[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    String succ = tmpBkReader.getFirstText("/ap/head/succ_flag");
                    if ("1".equals(succ) || "8".equals(succ)) {
                        WriteBankLogLn(tmpBkReader.getFirstText("/ap/head/ret_info"));
                    } else {
                        String fileName = tmpBkReader.getFirstText("/ap/body/file_name");
                        if (StringHelper.hasAnyChar(fileName)) {
                            downFile(pConfig, pReqReceipt, pOneDay, fileName);
                            retStr.append(fileName).append("_");
                            retStr.append(tmpBkReader.getFirstText("/ap/body/record_num")).append("_");
                            retStr.append(tmpBkReader.getFirstText("/ap/body/field_num"));
                        } else {
                            WriteBankLogLn("数据文件名为空");
                        }
                    }
                } else {
                    WriteBankLogLn(tmpSbMsg.toString());
                }
            } else {
                WriteBankLogLn(retStrArr[1]);
            }
        } catch (Exception e) {
            WriteBankLogLn("回单数据文件下载出错：" + e.getMessage());
        }
        return retStr.toString();
    }

    //查询回单PDF压缩文件
    private String downPDFFile(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay) {
        String qryDay8 = Format.Date8Format.format(pOneDay);
        try {
            String fileName = "";

            JSCB01Header header = new JSCB01Header();
            header.transCode = "700121";
            header.reqSeqNo = getQryTransID();

            XmlTextWriter xmlWriter = new XmlTextWriter();
            xmlWriter.autoFormat = false;
            writeCommonHeader(xmlWriter, header);
            xmlWriter.writeStartElement("body");
            xmlWriter.writeElementString("acno", pReqReceipt.actNum);
            xmlWriter.writeElementString("query_date", qryDay8);
            xmlWriter.writeElementString("reserved", "");
            xmlWriter.writeEndDocument();

            WriteBankLogLn("查询回单PDF文件.....");
            String[] retStrArr = sendToBank(xmlWriter.toXmlString());
            //String[] retStrArr = new String[]{"","<ap><head><tr_code>200125</tr_code><cms_corp_no>2011262835</cms_corp_no><user_no>001</user_no><req_no>A0001120200110080000011</req_no><serial_no>28235566</serial_no><tr_acdt>20200227</tr_acdt><tr_time>172335</tr_time><succ_flag>0</succ_flag><ret_info>交易成功</ret_info><ret_code>0000</ret_code><ext_info></ext_info><reserved></reserved><file_flag>1</file_flag><org_code>2056</org_code></head><body><record_num>113</record_num><host_serial_no>28235567</host_serial_no><stat>1</stat><file_name>70010188000056832_20190617.zip</file_name><field_num>40</field_num></body></ap>"};

            if (retStrArr[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                XmlTextReader tmpBkReader = loadBankRespXmlReader(retStrArr[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    String succ = tmpBkReader.getFirstText("/ap/head/succ_flag");
                    if ("1".equals(succ) || "8".equals(succ)) {
                        WriteBankLogLn(tmpBkReader.getFirstText("/ap/head/ret_info"));
                    } else {
                        String stat = tmpBkReader.getFirstText("/ap/body/stat");
                        if ("1".equals(stat)) {
                            fileName = tmpBkReader.getFirstText("/ap/body/file_name");
                        } else {
                            WriteBankLogLn("PDF文件生成失败");
                        }
                    }
                } else {
                    WriteBankLogLn(tmpSbMsg.toString());
                }
            } else {
                WriteBankLogLn(retStrArr[1]);
            }

            if (StringHelper.hasAnyChar(fileName)) {
                downFile(pConfig, pReqReceipt, pOneDay, fileName);
            } else {
                return null;
            }

            String localpath = pConfig.getSaveSubDir(pReqReceipt.reqHeader, pOneDay) + File.separator + qryDay8;
            FileHelper.mkdirsIfNotExists(localpath);

            if (fileName.toLowerCase().endsWith(".zip")) {
                String zipFile = localpath + File.separator + fileName;
                if (new File(zipFile).exists()) {
                    WriteBankLogLn("开始解压文件:" + zipFile);
                    ZipHelper.unzipFile(zipFile, localpath);
                    WriteBankLogLn("文件解压已完成.");
                    File depressDir = new File(localpath);
                    File[] deFiles = depressDir.listFiles();
                    if (deFiles == null || deFiles.length <= 0) {
                        WriteBankLogLn("解压后文件夹" + localpath + "下为空");
                    }
                } else {
                    WriteBankLogLn(fileName + "--该文件下载失败");
                }
            }
            return localpath + File.separator + fileName.substring(0, fileName.lastIndexOf(".zip"));

        } catch (Exception e) {
            WriteBankLogLn("PDF文件下载出错：" + e.getMessage());
        }
        return null;
    }

    public void downFile(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay, String fileName) throws Exception {
        String qryDay8 = Format.Date8Format.format(pOneDay);
        String receiptDownType = getBankConfig().getValueAsString("receiptDownType");
        String localpath = pConfig.getSaveSubDir(pReqReceipt.reqHeader, pOneDay) + File.separator + qryDay8;
        FileHelper.mkdirsIfNotExists(localpath);
        WriteBankLogLn("江苏银行文件下载目录：" + localpath + "，下载文件名：" + fileName);
        if ("sftp".equals(receiptDownType)) {
            //Sftp方式
            SftpPortClient sftpPortClient = null;
            try {
                FtpSet ftpSet = bankFront.getFtpSet("receipt");
                ftpSet.downDir = StringHelper.trimEnd(ftpSet.downDir, "/") + "/";
                WriteBankLogLn("SFTP下载地址" + ftpSet.serverIP + ":" + ftpSet.port);

                sftpPortClient = new SftpPortClient(ftpSet);
                WriteBankLogLn("下载到本地目录为：" + localpath);
                WriteBankLogLn("sftp目录下文件名为：" + fileName);
                FtpReceiver ftpReceiver = sftpPortClient.downloadFileByName("", localpath, fileName);
                if (ftpReceiver.isCompleted) {
                    WriteBankLogLn("下载成功，下载路径为：" + localpath + "文件名为" + fileName);
                } else {
                    WriteBankLogLn("下载失败，文件名为" + fileName);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                WriteBankLogLn(ex);
            } finally {
                if (sftpPortClient != null) {
                    sftpPortClient.disconnect();
                }
            }
        } else if ("ftp".equals(receiptDownType)) {
            FtpSet ftpSet = bankFront.getFtpSet("receipt");
            FtpPortClient client = new FtpPortClient(ftpSet);
            FtpReceiver ftpReceiver = client.downloadFile(fileName, localpath);
            if (!ftpReceiver.isCompleted) {
                WriteBankLogLn(ftpReceiver.connMsg);
            } else if (ConnState.FAIL.equals(ftpReceiver.connState)) {
                WriteBankLogLn("下载失败");
            } else {
                WriteBankLogLn("下载成功");
            }
        } else {
            //共享目录方式
            if (StringHelper.hasAnyChar(bankFront.bkTransFolder)) {
                if (bankFront.bkTransFolder.startsWith("smb://")) {
                    StringBuilder smbSb = new StringBuilder();
                    SmbFileUtil.smbDownload(localpath, bankFront.bkTransFolder, fileName, smbSb);
                } else {
                    String srcFilePath = StringHelper.trimEndFileSp(bankFront.bkTransFolder) + File.separator + fileName;
                    FileHelper.copyFile(srcFilePath, localpath + File.separator + fileName);
                }
            } else {
                throw new Exception("请配置银行前置机回单目录");
            }
        }
    }

}
